package com.zf.museum.shiro;

import com.zf.museum.shiro.AdminRealm;
import com.zf.museum.shiro.CustomizedModularRealmAuthenticator;
import com.zf.museum.shiro.CustomizedToken;
import com.zf.museum.shiro.UserRealm;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.authc.pam.AtLeastOneSuccessfulStrategy;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.handler.SimpleMappingExceptionResolver;


import java.util.*;

@Configuration
public class ShiroConfig {

    @Bean
    public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {

        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        /*拦截器*/
        Map<String,String> filterChainDefinitionMap = new LinkedHashMap<>();
        /*配置不会被拦截的链接 顺序判断*/
        filterChainDefinitionMap.put("/**", "anon");
        filterChainDefinitionMap.put("/museum/**", "anon");
        filterChainDefinitionMap.put("/**/login", "anon");
        filterChainDefinitionMap.put("/login.html", "anon");
        filterChainDefinitionMap.put("/user/getOpenId", "anon");
        //filterChainDefinitionMap.put("/swagger-ui.html", "anon");
        /*配置退出 过滤器,其中的具体的退出代码Shiro已经替我们实现了
        filterChainDefinitionMap.put("/logout", "logout");
        <!-- 过滤链定义，从上向下顺序执行，一般将/**放在最为下边 -->:这是一个坑呢，一不小心代码就不好使了;
        <!-- authc:所有url都必须认证通过才可以访问; anon:所有url都都可以匿名访问-->*/
        //filterChainDefinitionMap.put("/**", "authc");
        /*如果不设置默认会自动寻找Web工程根目录下的"/login.html"页面*/
        shiroFilterFactoryBean.setLoginUrl("/login.html");
        /* 登录成功后要跳转的链接*/
        //shiroFilterFactoryBean.setSuccessUrl("/index");
        /*未授权界面*/
        shiroFilterFactoryBean.setUnauthorizedUrl("/login.html");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);

        return shiroFilterFactoryBean;
    }

    /**
     * 凭证匹配器
     * （由于我们的密码校验交给Shiro的SimpleAuthenticationInfo进行处理了
     * ）
     * @return
     */
    @Bean
    public HashedCredentialsMatcher hashedCredentialsMatcher(){

        HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
        /*散列算法:这里使用MD5算法;*/
        hashedCredentialsMatcher.setHashAlgorithmName("md5");
        /*散列的次数，比如散列两次，相当于 md5(md5(""))*/
        hashedCredentialsMatcher.setHashIterations(2);

        return hashedCredentialsMatcher;
    }

    @Bean
    public UserRealm userRealm(){

        UserRealm userRealm = new UserRealm();
        userRealm.setCredentialsMatcher(hashedCredentialsMatcher());
        return userRealm;
    }

    @Bean
    public AdminRealm adminRealm() {

        AdminRealm adminRealm = new AdminRealm();
        adminRealm.setCredentialsMatcher(hashedCredentialsMatcher());
        return adminRealm;
    }

    @Bean
    public CustomizedModularRealmAuthenticator customizedModularRealmAuthenticator() {
        /*自己重写的ModularRealmAuthenticator*/
        CustomizedModularRealmAuthenticator customizedModularRealmAuthenticator = new CustomizedModularRealmAuthenticator();
        customizedModularRealmAuthenticator.setAuthenticationStrategy(new AtLeastOneSuccessfulStrategy());

        return customizedModularRealmAuthenticator;
    }

    @Bean
    public SecurityManager securityManager(){

        DefaultWebSecurityManager securityManager =  new DefaultWebSecurityManager();
        /*设置realm*/
        securityManager.setAuthenticator(customizedModularRealmAuthenticator());
        /*添加多个realm*/
        List<Realm> realms = new ArrayList<>();
        realms.add(userRealm());
        realms.add(adminRealm());
        securityManager.setRealms(realms);

        return securityManager;
    }

    /**
     *  开启shiro aop注解支持.
     *  使用代理方式;所以需要开启代码支持;
     * @param securityManager
     * @return
     */
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager){

        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);

        return authorizationAttributeSourceAdvisor;
    }

    @Bean(name="simpleMappingExceptionResolver")
    public SimpleMappingExceptionResolver createSimpleMappingExceptionResolver() {

        SimpleMappingExceptionResolver r = new SimpleMappingExceptionResolver();
        Properties mappings = new Properties();
        mappings.setProperty("DatabaseException", "databaseError");//数据库异常处理
        mappings.setProperty("UnauthorizedException","403");
        r.setExceptionMappings(mappings);  // None by default
        r.setDefaultErrorView("error");    // No default
        r.setExceptionAttribute("ex");     // Default is "exception"
        //r.setWarnLogCategory("example.MvcLogger");     // No default

        return r;
    }
}
